package fr.mywiki.business.account;

import java.rmi.RemoteException;
import java.sql.SQLException;
import java.util.Random;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import fr.mywiki.business.account.AccountManager;
import fr.mywiki.business.profil.Profile;
import fr.mywiki.business.utils.MD5;
import fr.mywiki.model.ejbAdapter.DataController;
import fr.mywiki.model.queries.DatabaseAdapter;
import fr.mywiki.model.queries.ResultList;

/** 
 * Testing AccountManager class.
 * 
 * @see http://localhost:8080/MyWiki/ServletTestRunner?suite=fr.mywiki.business.account.AccountManagerTest&xsl=cactus-report.xsl 
 */
public class AccountManagerTest extends TestCase {
	static final String login1 = "afirstlogin";
	static final String login2 = "asecundlogin";
	static final String pwd1 = "afirstpassword";
	static final String pwd2 = "asecundpassword";

	static final String login1bis = "aloginmodified";

	static AccountLite account1, account2;

	protected void setUp() {}

	protected void tearDown() {}

	public AccountManagerTest(String a_name) {
		super(a_name);
	}

	public static Test suite() {
		TestSuite suite = new TestSuite();
		suite.addTestSuite(AccountManagerTest.class);

		return suite;
	}

	/**
	 * Creates several accounts and checks in the database, by the returned
	 * AccountLite object and by regenerated AccountLite objects if they have
	 * been correctly created.
	 */
	public void testCreateAccount() {
		try {
			account1 = AccountManager
					.createAccount(login1, pwd1, Profile.ADMIN, null);
			account2 = AccountManager.createAccount(login2, pwd2,
					Profile.AUTHOR, null);
		} catch (Exception e) {
			fail("Exception at the creation of the accounts.");
		}

		/* Checking the AccountLite objects */
		assertEquals(login1, account1.getLogin());
		assertEquals(MD5.asHex(pwd1.getBytes()), account1.getPassword());
		assertEquals(Profile.ADMIN, account1.getProfile());

		assertEquals(login2, account2.getLogin());
		assertEquals(MD5.asHex(pwd2.getBytes()), account2.getPassword());
		assertEquals(Profile.AUTHOR, account2.getProfile());

		/* Reloading and checking the AccountLite objects */
		AccountLite acc1 = null;
		AccountLite acc2 = null;
		try {
			acc1 = (AccountLite) DataController.getValue(account1.getId(),
					AccountLite.TYPE_ENT);
			acc2 = (AccountLite) DataController.getValue(account2.getId(),
					AccountLite.TYPE_ENT);
		} catch (RemoteException e) {
			fail("GetValue");
		}
		assertEquals(login1, acc1.getLogin());
		assertEquals(MD5.asHex(pwd1.getBytes()), acc1.getPassword());
		assertEquals(Profile.ADMIN, acc1.getProfile());

		assertEquals(login2, acc2.getLogin());
		assertEquals(MD5.asHex(pwd2.getBytes()), acc2.getPassword());
		assertEquals(Profile.AUTHOR, acc2.getProfile());

		/* Checking in the database */
		String sql = "SELECT login, password, profileId FROM account WHERE id="
				+ account1.getId().toString();
		ResultList results = null;
		try {
			results = DatabaseAdapter.executeSelectQuery(sql);
		} catch (SQLException e) {
			fail("First query execution");
		}
		assertEquals(1, results.getRecordsCount());
		Object[] array = results.getRecord(0);
		assertEquals(login1, array[0]);
		assertEquals(MD5.asHex(pwd1.getBytes()), (String) array[1]);
		assertEquals(Profile.ADMIN_PROFILE_ID, array[2]);

		sql = "SELECT login, password, profileId FROM account WHERE id="
				+ account2.getId().toString();
		results = null;
		try {
			results = DatabaseAdapter.executeSelectQuery(sql);
		} catch (SQLException e) {
			fail("First query execution");
		}
		assertEquals(1, results.getRecordsCount());
		array = results.getRecord(0);
		assertEquals(login2, array[0]);
		assertEquals(MD5.asHex(pwd2.getBytes()), (String) array[1]);
		assertEquals(Profile.AUTHOR_PROFILE_ID, array[2]);
	}

	/**
	 * Modifies account1 and checks (still by different ways) if it has been
	 * correctly modified.
	 */
	public void testModifyAccount() {
		try {
			AccountManager.modifyAccount(account1, login1bis, Profile.AUTHOR, null);
		} catch (Exception e) {
			fail("Account modification");
		}

		/* Checking the AccountLite objects */
		assertEquals(login1bis, account1.getLogin());
		assertEquals(MD5.asHex(pwd1.getBytes()), account1.getPassword());
		assertEquals(Profile.AUTHOR, account1.getProfile());

		/* Reloading and checking the AccountLite objects */
		AccountLite acc1 = null;
		try {
			acc1 = (AccountLite) DataController.getValue(account1.getId(),
					AccountLite.TYPE_ENT);
		} catch (RemoteException e) {
			fail("GetValue");
		}
		assertEquals(login1bis, acc1.getLogin());
		assertEquals(MD5.asHex(pwd1.getBytes()), acc1.getPassword());
		assertEquals(Profile.AUTHOR, acc1.getProfile());

		/* Checking in the database */
		String sql = "SELECT login, password, profileId FROM account WHERE id="
				+ account1.getId().toString();
		ResultList results = null;
		try {
			results = DatabaseAdapter.executeSelectQuery(sql);
		} catch (SQLException e) {
			fail("First query execution");
		}
		assertEquals(1, results.getRecordsCount());
		Object[] array = results.getRecord(0);
		assertEquals(login1bis, array[0]);
		assertEquals(MD5.asHex(pwd1.getBytes()), (String) array[1]);
		assertEquals(Profile.AUTHOR_PROFILE_ID, array[2]);
	}

	/**
	 * Searches for an existant account, must find it. Then searches for an
	 * inexistant account, must not find it.
	 */
	public void testFindAccount() {
		AccountLite searched = AccountManager.findAccount(login2);
		assertNotNull(searched);
		assertEquals(account2, searched);

		searched = AccountManager.findAccount(Integer.toString(new Random()
				.nextInt()));
		assertNull(searched);
	}

	public void testRemoveAccount() {
		Long id1 = account1.getId();
		Long id2 = account2.getId();
		try {
			account1.remove();
			account2.remove();
		} catch (Exception e) {
			fail("Remove accounts");
		}

		try {
			account1 = (AccountLite) DataController.getValue(id1,
					AccountLite.TYPE_ENT);
			account2 = (AccountLite) DataController.getValue(id2,
					AccountLite.TYPE_ENT);
		} catch (RemoteException e) {
			fail("Get values");
		}
		assertNull(account1);
		assertNull(account2);
	}
}
